package com.luoke.service.impl;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.luoke.constant.ModuleTypeConstant;
import com.luoke.constant.SubmoduleTypeConstant;
import com.luoke.context.GlobalDataStore;
import com.luoke.dao.*;
import com.luoke.dao.impl.*;
import com.luoke.pojo.dto.BagDTO;
import com.luoke.pojo.dto.BattleInfoDTO;
import com.luoke.pojo.dto.BattleRoundDTO;
import com.luoke.pojo.dto.PetChooseDTO;
import com.luoke.pojo.entity.*;
import com.luoke.result.Result;
import com.luoke.service.BattleRoundResponseService;
import com.luoke.util.BattleUtils;
import com.luoke.util.myjdbc.QueryWrapper;
import com.luoke.util.myjdbc.UpdateWrapper;
import org.java_websocket.WebSocket;

import java.util.List;
import java.util.Optional;
import java.util.Random;
import java.util.stream.Collectors;

public class BattleRoundResponseServiceImpl implements BattleRoundResponseService {

    private final BattleDao battleDao = new BattleDaoImpl();
    private final UserDao userDao = new UserDaoImpl();
    private final BagDao bagDao = new BagDaoImpl();
    private final BatterPetDao batterPetDao = new BattlePetDaoImpl();
    private final SkillDao skillDao = new SkillDaoImpl();
    private final AttributeDao attributeDao = new AttributeDaoImpl();


    /**
     * 对客户端发来的宠物选择进行响应，写入数据库
     *
     * @param conn   连接对象
     * @param result 请求对象
     */
    @Override
    public void firstPetChoose(WebSocket conn, Result result) {
        PetChooseDTO petChooseDTO = JSONUtil.toBean(result.getData().toString(), PetChooseDTO.class);
        result.setData(petChooseDTO);
        battleDao.savePetChoose(petChooseDTO);
        // 每次选择宠物时都要调用这个方法
        firstHandResponse(petChooseDTO);
    }

    /**
     * 向客户端发送先手回合的玩家名称
     *
     * @param petChooseDTO 宠物选择DTO
     */
    @Override
    public void firstHandResponse(PetChooseDTO petChooseDTO) {
        int initiatorActive = battleDao.getBattlePetIsActive(petChooseDTO.getInitiatorName());
        int opponentActive = battleDao.getBattlePetIsActive(petChooseDTO.getOpponentName());

        // 当双方都选择了宠物后执行
        if (initiatorActive > 0 && opponentActive > 0) {
            String initiatorName = petChooseDTO.getInitiatorName();
            String opponentName = petChooseDTO.getOpponentName();

            // 查询战斗宠物表获得用户对应的宠物信息
            BattleInfoDTO battleInfoDTO = batterPetDao.getBattlePlayerInfo(
                    GlobalDataStore.getBattleIdByPlayerName(initiatorName)
            );
            battleInfoDTO.setActivePetByPlayerName(
                    battleInfoDTO.getPlayer1Name(), battleInfoDTO.getPlayer1ActivePet(), attributeDao
            );
            battleInfoDTO.setActivePetByPlayerName(
                    battleInfoDTO.getPlayer2Name(), battleInfoDTO.getPlayer2ActivePet(), attributeDao
            );
            // 保存战斗信息到上下文
            GlobalDataStore.addPlayerToBattle(initiatorName, battleInfoDTO);
            GlobalDataStore.addPlayerToBattle(opponentName, battleInfoDTO);

            // 进行敏捷度比较，判断谁是先手
            System.out.println("双方都选择了宠物，现在进行比较");

            int initiatorDexterity = battleDao.getPetDexterityByBattleUsername(initiatorName);
            int opponentDexterity = battleDao.getPetDexterityByBattleUsername(opponentName);

            String firstHandPlayer;
            String secondPlayer;
            BattleRoundDTO roundDTO = getBattleRoundDTO(petChooseDTO);

            if (initiatorDexterity == opponentDexterity) {
                // 敏捷度相等，随机选择先手
                if (new Random().nextBoolean()) {
                    firstHandPlayer = initiatorName;
                    secondPlayer = opponentName;
                } else {
                    firstHandPlayer = opponentName;
                    secondPlayer = initiatorName;
                }
            } else if (initiatorDexterity > opponentDexterity) {
                firstHandPlayer = initiatorName;
                secondPlayer = opponentName;
            } else {
                firstHandPlayer = opponentName;
                secondPlayer = initiatorName;
            }

            // 发送消息给先手玩家
            sendFirstHandResponse(firstHandPlayer, "你获得了对局先手权", roundDTO);
            // 发送消息给后手玩家
            sendFirstHandResponse(secondPlayer, "对方获得了对局先手权，请等待对方出招", secondPlayer);
        }
    }

    /**
     * 发送先手或后手消息给客户端
     *
     * @param playerName 接收消息的玩家名称
     * @param message    消息内容
     * @param data       附带的数据
     */
    private void sendFirstHandResponse(String playerName, String message, Object data) {
        GlobalDataStore.onlineUser.get(playerName)
                .send(JSONUtil.toJsonStr(Result.success(
                        SubmoduleTypeConstant.FIRST_HAND_RESPONSE,
                        ModuleTypeConstant.BATTLE_ROUND,
                        message,
                        data
                )));
    }

    /**
     * 创建包含双方宠物信息的数据传输对象 (DTO)，用于在响应消息中发送双方的宠物状态。
     *
     * @param petChooseDTO 双方宠物信息DTO
     * @return 战斗回合信息DTO
     */
    private BattleRoundDTO getBattleRoundDTO(PetChooseDTO petChooseDTO) {
        List<BattlePet> pets = battleDao.getBattlePetList(petChooseDTO.getInitiatorName());
        User initiatorUser = userDao.getUserByName(petChooseDTO.getInitiatorName());

        BattlePet initiatorPet = pets.stream()
                .filter(pet -> pet.getOwnerPlayerId().equals(initiatorUser.getId()))
                .findFirst()
                .orElse(null);

        BattlePet opponentPet = pets.stream()
                .filter(pet -> !pet.getOwnerPlayerId().equals(initiatorUser.getId()))
                .findFirst()
                .orElse(null);

        BattleRoundDTO roundDTO = new BattleRoundDTO();
        roundDTO.setInitiatorName(petChooseDTO.getInitiatorName());
        roundDTO.setOpponentName(petChooseDTO.getOpponentName());

        BattleInfoDTO battleInfoDTO = GlobalDataStore.getBattleInfoByPlayerName(initiatorUser.getName());
        Attribute player1Attribute = battleInfoDTO.getPlayer1PetAttribute();
        Attribute player2Attribute = battleInfoDTO.getPlayer2PetAttribute();

        if (initiatorUser.getName().equals(battleInfoDTO.getPlayer1Name())) {
            populateRoundDTO(roundDTO, initiatorPet, opponentPet, battleInfoDTO, player1Attribute, player2Attribute);
        } else {
            populateRoundDTO(roundDTO, opponentPet, initiatorPet, battleInfoDTO, player2Attribute, player1Attribute);
        }
        return roundDTO;
    }

    /**
     * 填充 BattleRoundDTO 对象
     *
     * @param roundDTO           回合数据传输对象
     * @param initiatorPet       发起者的宠物
     * @param opponentPet        对手的宠物
     * @param battleInfoDTO      战斗信息
     * @param initiatorAttribute 发起者宠物属性
     * @param opponentAttribute  对手宠物属性
     */
    private void populateRoundDTO(BattleRoundDTO roundDTO,
                                  BattlePet initiatorPet,
                                  BattlePet opponentPet,
                                  BattleInfoDTO battleInfoDTO,
                                  Attribute initiatorAttribute,
                                  Attribute opponentAttribute) {

        roundDTO.setInitiatorPetName(initiatorPet.getPetName());
        roundDTO.setInitiatorPetId(initiatorPet.getId());
        roundDTO.setInitiatorPetHp(initiatorPet.getHp());
        roundDTO.setInitiatorPetMp(initiatorPet.getMp());
        roundDTO.setInitiatorPetLevel(battleInfoDTO.getPlayer1PetLevel());
        roundDTO.setInitiatorPetMain(initiatorAttribute.getMain());

        roundDTO.setOpponentPetName(opponentPet.getPetName());
        roundDTO.setOpponentPetId(opponentPet.getId());
        roundDTO.setOpponentPetHp(opponentPet.getHp());
        roundDTO.setOpponentPetMp(opponentPet.getMp());
        roundDTO.setOpponentPetLevel(battleInfoDTO.getPlayer2PetLevel());
        roundDTO.setOpponentPetMain(opponentAttribute.getMain());
    }


    /**
     * 获取背包
     *
     * @param conn   连接对象
     * @param result 请求对象
     */
    @Override
    public void getBag(WebSocket conn, Result result) {

        List<BagDTO> battleBags = bagDao.getUserBagByUsername(result.getData().toString());
        Result response = new Result();
        response.setModuleName(ModuleTypeConstant.BATTLE_ROUND);
        response.setCommand(SubmoduleTypeConstant.BAG); //这里还需要设置子模块的名称
        response.setStatus("success");
        response.setData(battleBags);
        response.setFromUser(result.getData().toString());
        String s = BattleUtils.getOpponentPlayerName(result.getData().toString());
        response.setToUser(s);
        conn.send(JSONUtil.toJsonStr(response)); //把成功的消息响应给客户端
        System.out.println(result.getData() + "获取战斗中背包信息");
    }

    /**
     * 用于处理战斗回合的逻辑,实现了回合制战斗的回合切换和状态同步功能
     *
     * @param conn   连接对象
     * @param result 请求对象
     */
    @Override
    public void turnAurond(WebSocket conn, Result result) {
        //获取旧的用户名和用户对象：
        String fromUserName = result.getFromUser();
        String toUserName = result.getToUser();
        //分别拿到发起玩家和目标玩家
        User fromUser = userDao.getUserByName(fromUserName);
        User toUser = userDao.getUserByName(toUserName);

        //将result.getData()转换为JSONObject
        JSONObject jsonObject = JSONUtil.parseObj(result.getData());
        /*
                这里使用的是java8的Optional.ofNullable方法，如果jsonObject中的type字段不存在，则返回Optional.empty()
         */

        // 处理道具使用
        handleItemUse(jsonObject, fromUserName, toUser, fromUser, result);

        // 处理宠物切换
        handlePetSwitch(jsonObject, fromUserName, result, fromUser);

        // 处理攻击
        handleAttack(jsonObject, fromUserName, result, fromUser);

    }

    /**
     * 更新回合信息并发送给对手
     *
     * @param fromUserName 发起方
     * @param fromUser     发起方对象
     */
    private BattleRoundDTO sendTurnAroundResponse(String fromUserName, User fromUser) {
        List<BattlePet> pets = battleDao.getBattlePetList(fromUserName);  //获取在战斗中所有出战的宠物信息
        Battle battle = (Battle) battleDao.selectOneById(GlobalDataStore.getBattleIdByPlayerName(fromUserName), Battle.class); //根据战斗ID获取战斗信息
        /*
        下面两行代码用于区分双方的宠物
                使用Stream和filter：
                从pets列表中筛选出属于当前玩家的宠物battlePet。
                筛选出属于对手玩家的宠物battlePet2。
         */
        //这里做了二次判断,筛选出第一只
        BattlePet battlePet = pets.stream().filter(i -> i.getOwnerPlayerId().equals(fromUser.getId())).collect(Collectors.toList()).get(0);
        BattlePet battlePet2 = pets.stream().filter(i -> !i.getOwnerPlayerId().equals(fromUser.getId())).collect(Collectors.toList()).get(0);
        //构建回合信息对象
        BattleRoundDTO roundDTO = new BattleRoundDTO();
        roundDTO.setInitiatorName(battle.getInitiatorName());
        roundDTO.setOpponentName(battle.getOpponentName());
        /*
            判断当前玩家是否为战斗的发起者
            如果是，则将当前玩家的宠物信息设置为发起者的宠物，另一个宠物设置为对手的宠物。
            如果不是，则反转双方的宠物信息。
         */
        BattleInfoDTO battleInfoDTO = GlobalDataStore.getBattleInfoByPlayerName(fromUserName);
        Attribute player1PetAttribute = battleInfoDTO.getPlayer1PetAttribute();
        Attribute player2PetAttribute = battleInfoDTO.getPlayer2PetAttribute();
        if (fromUserName.equals(battleInfoDTO.getPlayer1Name())) {
            //当前玩家是发起者
            roundDTO.setInitiatorPetName(battlePet.getPetName());
            roundDTO.setInitiatorPetId(battlePet.getId());
            roundDTO.setInitiatorPetHp(battlePet.getHp());
            roundDTO.setInitiatorPetMp(battlePet.getMp());
            roundDTO.setInitiatorPetLevel(battleInfoDTO.getPlayer1PetLevel());
            roundDTO.setInitiatorPetMain(player1PetAttribute.getMain());

            roundDTO.setOpponentPetName(battlePet2.getPetName());
            roundDTO.setOpponentPetId(battlePet2.getId());
            roundDTO.setOpponentPetHp(battlePet2.getHp());
            roundDTO.setOpponentPetMp(battlePet2.getMp());
            roundDTO.setOpponentPetLevel(battleInfoDTO.getPlayer2PetLevel());
            roundDTO.setOpponentPetMain(player2PetAttribute.getMain());
        } else {
            //当前玩家是对手，
            roundDTO.setInitiatorPetName(battlePet2.getPetName());
            roundDTO.setInitiatorPetId(battlePet2.getId());
            roundDTO.setInitiatorPetHp(battlePet2.getHp());
            roundDTO.setInitiatorPetMp(battlePet2.getMp());
            roundDTO.setInitiatorPetLevel(battleInfoDTO.getPlayer2PetLevel());
            roundDTO.setInitiatorPetMain(player2PetAttribute.getMain());

            roundDTO.setOpponentPetName(battlePet.getPetName());
            roundDTO.setOpponentPetId(battlePet.getId());
            roundDTO.setOpponentPetHp(battlePet.getHp());
            roundDTO.setOpponentPetMp(battlePet.getMp());
            roundDTO.setOpponentPetLevel(battleInfoDTO.getPlayer1PetLevel());
            roundDTO.setOpponentPetMain(player1PetAttribute.getMain());
        }

        return roundDTO;


    }

    /**
     * 响应情况1
     *
     * @param fromUserName 发起方
     * @param roundDTO     回合信息数据传输对象
     * @param result       请求对象
     */
    public void sendMessage1(String fromUserName, BattleRoundDTO roundDTO, Result result) {
        //构建响应消息
        Result response = new Result();
        response.setModuleName(ModuleTypeConstant.BATTLE_ROUND);
        response.setCommand(SubmoduleTypeConstant.OPPONENT_ROUND_COMPLETED); //这里还需要设置子模块的名称
        response.setStatus("success");
        response.setData(roundDTO);
        response.setMessage(result.getMessage());

        response.setFromUser(fromUserName);//TODO 2024年11月28日17:31:55
        WebSocket webSocket = GlobalDataStore.onlineUser.get(fromUserName); //TODO 2024年11月28日17:33:38
        webSocket.send(JSONUtil.toJsonStr(response)); //把成功的消息响应给客户端
        System.out.println("到" + fromUserName + "回合"); //TODO 2024年11月28日17:32:26
    }

    /**
     * 响应情况2
     *
     * @param fromUserName 发起方
     * @param roundDTO     回合信息数据传输对象
     * @param result       请求对象
     */
    public void sendMessage2(String fromUserName, BattleRoundDTO roundDTO, Result result) {
        //构建响应消息
        Result response = new Result();
        response.setModuleName(ModuleTypeConstant.BATTLE_ROUND);
        response.setCommand(SubmoduleTypeConstant.OPPONENT_ROUND_COMPLETED); //这里还需要设置子模块的名称
        response.setStatus("success");
        response.setData(roundDTO);
        response.setMessage(result.getMessage());

        response.setFromUser(BattleUtils.getOpponentPlayerName(fromUserName));//TODO 2024年11月28日17:31:55
        WebSocket webSocket = GlobalDataStore.onlineUser.get(BattleUtils.getOpponentPlayerName(fromUserName)); //TODO 2024年11月28日17:33:38
        webSocket.send(JSONUtil.toJsonStr(response)); //把成功的消息响应给客户端
        System.out.println("到" + BattleUtils.getOpponentPlayerName(fromUserName) + "回合"); //TODO 2024年11月28日17:32:26
    }

    /**
     * 处理道具使用
     *
     * @param jsonObject   发起方携带的数据
     * @param fromUserName 发起方
     * @param toUser       目标玩家对象
     * @param fromUser     发起方对象
     * @param result       请求对象
     */
    private void handleItemUse(JSONObject jsonObject, String fromUserName, User toUser, User fromUser, Result result) {
        Optional.ofNullable(jsonObject.getStr("type")).ifPresent(i -> {  //这个i值是type的值
            String me = BattleUtils.getOpponentPlayerName(fromUserName);//找到对手用户的name
            User meUser = userDao.getUserByName(me);
            if (i.equals("道具")) {
                String name = jsonObject.getStr("goodsName");
                if (name.contains("蓝瓶")) {
                    /*
                        为当前用户的战斗宠物增加MP。jsonObject.getInt("value")是道具的数值，meUser.getId()是对手用户的ID。
                     */
                    //TODO 2024年11月28日18:55:45
                    battleDao.updateBattlePetMp(fromUserName, jsonObject.getInt("value"), meUser.getId());
                    //扣减背包中对应的道具数量,首先要判断是否道具数量-1后是否为0，为0则直接执行删除操作
                    if (jsonObject.getInt("quantity") - 1 == 0) {
                        bagDao.deleteBagQuantityByGoodsNameAndUserId(jsonObject.getStr("goodsName"), toUser.getId());
                    } else {
                        bagDao.updateBagQuantityByGoodsNameAndUserId(jsonObject.getStr("goodsName"), toUser.getId(), jsonObject.getInt("quantity"));
                    }
                }
                if (name.contains("红瓶")) {
                    battleDao.updateBattlePetHp(fromUserName, jsonObject.getInt("value"), meUser.getId());
                }
            }

            BattleRoundDTO battleRoundDTO = sendTurnAroundResponse(fromUserName, fromUser);
            sendMessage1(fromUserName, battleRoundDTO, result); //发送消息

        });
    }

    /**
     * 处理宠物切换
     *
     * @param jsonObject   发起方携带的数据
     * @param fromUserName 发起方
     * @param result       请求对象
     * @param fromUser     发起方对象
     */
    private void handlePetSwitch(JSONObject jsonObject, String fromUserName, Result result, User fromUser) {
        Optional.ofNullable(jsonObject.getLong("ownerPlayerId")).ifPresent(i -> {
            UpdateWrapper<BattlePet> old = new UpdateWrapper<>();
            old.update(BattlePet.class)
                    .set(BattlePet::getIsActive, "0")  //将旧宠物的状态设为非激活
                    .where(BattlePet::getBattleId, GlobalDataStore.getBattleIdByPlayerName(fromUserName).toString())
                    .and(BattlePet::getOwnerPlayerId, i.toString())
            ;
            batterPetDao.update(old);
            UpdateWrapper<BattlePet> uw = new UpdateWrapper<>();
            uw.update(BattlePet.class)
                    .set(BattlePet::getIsActive, "1") //激活选择的宠物
                    .where(BattlePet::getId, jsonObject.getLong("id").toString());
            batterPetDao.update(uw);
            //通过id得到name
            QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
            userQueryWrapper.select(User::getName).from(User.class).where(User::getId, i.toString());
            User user = userDao.selectOne(userQueryWrapper);
            //通过name拿到本对局的对战信息
            BattleInfoDTO battleInfoByPlayerName = GlobalDataStore.getBattleInfoByPlayerName(user.getName());
            //修改对战信息中的宠物信息
            battleInfoByPlayerName.setActivePetByPlayerName(user.getName(), jsonObject.getStr("petName"), attributeDao);

            BattleRoundDTO battleRoundDTO = sendTurnAroundResponse(fromUserName, fromUser);
            sendMessage1(fromUserName, battleRoundDTO, result); //发送消息

        });
    }

    /**
     * 处理攻击
     *
     * @param jsonObject   发起方携带的数据
     * @param fromUserName 发起方
     * @param result       请求对象
     * @param fromUser     发起方对象
     */
    private void handleAttack(JSONObject jsonObject, String fromUserName, Result result, User fromUser) {
        Optional.ofNullable(jsonObject.getInt("needMp")).ifPresent(i -> {
            //以下是线程不安全的方法
//            userName.set(GlobalDataStore.onlineUser.keySet().stream().filter(u -> !userName.get().equals(u)).collect(Collectors.toList()).get(0));
            //可以直接从全局仓库中取到另外一个玩家的名字
            UpdateWrapper<BattlePet> old = new UpdateWrapper<>();
            old.update(BattlePet.class)
                    .set(BattlePet::getMp, i.toString())
                    .where(BattlePet::getId, jsonObject.getInt("id").toString());
            batterPetDao.update(old);
            User user1 = userDao.getUserByName(BattleUtils.getOpponentPlayerName(fromUserName));

            BattlePet battlePet = batterPetDao.getOtherBattlePet(user1.getId(), fromUserName);
            Integer value = jsonObject.getInt("value");
            //这里要调用伤害计算工具类
            String message = BattleUtils.calculateDamage(fromUserName, BattleUtils.getOpponentPlayerName(fromUserName), value);
            //从描述中拿出伤害值
            int damage = BattleUtils.extractDamage(message);
            battlePet.setHp(battlePet.getHp() - damage);
            result.setMessage(result.getMessage() + message);
            if (battlePet.getHp() <= 0) {

                battlePet.setIsAlive(0);
                result.setMessage(result.getMessage() + "|你已死亡，重新选择宠物");
            }
            batterPetDao.updateById(battlePet);


            BattleRoundDTO battleRoundDTO = sendTurnAroundResponse(fromUserName, fromUser);
            sendMessage2(fromUserName, battleRoundDTO, result); //发送消息


        });
    }


    /**
     * 对于客户端在pvp对战中切换宠物的请求的处理
     *
     * @param conn   连接对象
     * @param result 请求对象
     */
    @Override
    public void getPetList(WebSocket conn, Result result) {
        String userName = result.getFromUser();
        User user = userDao.getUserByName(userName);

        List<BattlePet> battlePet = batterPetDao.getBatterPetList(user.getId(), userName);
        //如何获得的集合是空的则说明该玩家失败了，说明对局结束，这是要清除全局仓库中的信息
        if (battlePet == null) {
            BattleUtils.removeGlobalBattleMessage(userName, BattleUtils.getOpponentPlayerName(userName));
        }
        Result response = new Result();
        response.setModuleName(ModuleTypeConstant.BATTLE_ROUND);
        response.setCommand(SubmoduleTypeConstant.PETS); //这里还需要设置子模块的名称
        response.setStatus("success");
        response.setData(battlePet);
        response.setFromUser(userName);
        response.setToUser(BattleUtils.getOpponentPlayerName(userName));
        conn.send(JSONUtil.toJsonStr(response)); //把成功的消息响应给客户端
        System.out.println(userName + "获取宠物");
    }

    /**
     * 获取宠物技能表
     *
     * @param conn   连接对象
     * @param result 请求对象
     */
    @Override
    public void getSkillList(WebSocket conn, Result result) {
        String userName = result.getFromUser();
        String userPetName = result.getData().toString();

        List<Skill> skills1 = skillDao.getSkillByPetNameAndUsername(userName, userPetName);
        Result response = new Result();
        response.setModuleName(ModuleTypeConstant.BATTLE_ROUND);
        response.setCommand(SubmoduleTypeConstant.SKILLS); //这里还需要设置子模块的名称
        response.setStatus("success");
        response.setData(skills1);
        response.setFromUser(userName);
        response.setToUser(BattleUtils.getOpponentPlayerName(userName)); //获取敌方信息
        conn.send(JSONUtil.toJsonStr(response)); //把成功的消息响应给客户端
        System.out.println(userName + "获取技能");

    }


}
